package org.hidaron.example.demo.download.service;

import org.hidaron.asyncdownloader.R;
import org.hidaron.asyncdownloader.download.Downloader;
import org.hidaron.asyncdownloader.download.DownloaderOptions;
import org.hidaron.asyncdownloader.download.FileDownloader;
import org.hidaron.asyncdownloader.download.listener.OnDownloadListener;
import org.hidaron.asyncdownloader.download.queue.DownloaderTaskQueue;
import org.hidaron.asyncdownloader.download.queue.TaskQueue;
import org.hidaron.asyncdownloader.utils.NetWorkSpeedUtils;
import org.hidaron.asyncdownloader.utils.ToastUtils;
import org.hidaron.example.demo.DemoActivity;
import org.hidaron.example.demo.download.AppInfo;
import org.hidaron.example.demo.download.adapter.DownloadListAdapter.ViewHolder;

import android.app.Activity;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;

/**
 * 
 * @author hidaron <hidaron@163.com>
 * 
 */
public class DownloadService extends Service {
	private static final String TAG = DownloadService.class.getSimpleName();

	private IBinder mDownloadBinder;
	private DownloaderOptions mDownloadOptions;
	private NotificationManager mNotificationManager;
	private TaskQueue taskQueue;

	public class DownloadBinder extends Binder {

		public Downloader startDownload(Context context, AppInfo appInfo,
				Object holder) {
			return download(context, appInfo, holder);
		}

		public void continueDownload(Downloader downloader) {
			reDownload(downloader);
		}

		public void cancelDownload(Downloader downloader) {
			cancel(downloader);
		}

		public void cancelAllDownload() {
			cancelAll();
		}

		public void pauseDownload(Downloader downloader) {
			pause(downloader);
		}
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(TAG, "downloadservice onCreate");
		taskQueue = new DownloaderTaskQueue();
		mDownloadBinder = new DownloadBinder();
		mDownloadOptions = new DownloaderOptions.Builder().setDownLoadDir(
				DownloaderOptions.DEFAULT_DOWNLOADS_DIR).build();
		mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return mDownloadBinder;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.d(TAG, "onDestory");
		stopSelf();
		stopForeground(true);
		mNotificationManager.cancelAll();
	}

	@Override
	public boolean onUnbind(Intent intent) {
		taskQueue.removeAll();
		Log.d(TAG, "onUnbind");
		return super.onUnbind(intent);
	}

	private void sendNotification(int taskId, Notification notification) {
		mNotificationManager.notify(taskId, notification);
	}

	private void cancleNotification(int taskId) {
		mNotificationManager.cancel(taskId);
	}

	private void addDownloadTask(Downloader downloader) {
		if (null != downloader) {
			taskQueue.add(downloader);
		}
	}

	private class ServiceDownloadListener implements OnDownloadListener {
		private Context mContext;
		private ViewHolder mHolder;
		private AppInfo mAppInfo;
		private Downloader mDownloader;
		private int mContentLength;
		private ServiceNotificationFactory notificationFactory;
		private Notification notification;
		private int writtenBytesTotal;
		private long startTime;
		private long recordTime;
		private long writtingTime;
		private long outageTime;

		public void clearRecordTime() {
			recordTime = 0;
		}

		public ServiceDownloadListener(Context context, Object holder,
				AppInfo appInfo, Downloader downloader) {
			mContext = context;
			mHolder = (ViewHolder) holder;
			mAppInfo = appInfo;
			mDownloader = downloader;
		}

		@Override
		public void onStart(int contentLength, int writtenBytesLength,
				long firstTime) {
			Log.d(TAG, "download service start...");
			startTime = firstTime;
			mContentLength = contentLength;
			writtenBytesTotal = writtenBytesLength;
			Log.d(TAG, "download start wirttenByte " + writtenBytesTotal);
			mHolder.button.setText("取消");
			mHolder.pargressBar.setMax(mContentLength);
			mHolder.pargressBar.setVisibility(View.VISIBLE);
			mHolder.speed.setVisibility(View.VISIBLE);
			notificationFactory = new DownloadService.ServiceNotificationFactory(
					mContext);
		}

		@Override
		public void onSuccess(int statusCode, byte[] responseBody) {
			Log.d(TAG, "download service connect success...");
		}

		@Override
		public void onFailure(int statusCode, byte[] responseBody,
				Throwable error) {
			clearRecordTime();
			outageTime = System.currentTimeMillis();
			mHolder.button.setText("继续下载");
			mHolder.speed.setVisibility(View.INVISIBLE);
			RemoteViews views = new RemoteViews(getPackageName(),
					R.layout.view_download_notification);
			views.setTextViewText(R.id.title, mAppInfo.getAppName());
			views.setTextViewText(R.id.title_text,
					getResources().getString(R.string.download_failure));
			views.setViewVisibility(R.id.title_text, View.VISIBLE);
			views.setImageViewResource(R.id.icon, R.drawable.ic_launcher);
			views.setViewVisibility(R.id.progressbar, View.INVISIBLE);
			if (null == notificationFactory) {
				notificationFactory = new DownloadService.ServiceNotificationFactory(
						mContext);
			}
			notification = notificationFactory.create(views);
			notification.flags = Notification.FLAG_AUTO_CANCEL;
			sendNotification(getTaskId(mDownloader), notification);
			ToastUtils.warning((Activity) mContext, R.string.download_failure);
		}

		@Override
		public void onProgress(int bytesWritten, int totalSize) {
			writtenBytesTotal += bytesWritten;
			if (System.currentTimeMillis() - recordTime < 1 * 1000
					&& totalSize - writtenBytesTotal != 0) {
				return;
			}
			recordTime = System.currentTimeMillis();
			if (outageTime != 0) {
				writtingTime += System.currentTimeMillis() - outageTime;
			}
			long downloadSpeed = (long) (writtenBytesTotal == 0 ? 0
					: (writtenBytesTotal
							/ ((System.currentTimeMillis() - startTime - writtingTime) / 1000D) / 1024));
			outageTime = 0;
			mHolder.pargressBar.setProgress(writtenBytesTotal);
			Log.d(TAG, " max length" + mHolder.pargressBar.getMax() + "");
			Log.d(TAG,
					"writtenBytes length " + String.valueOf(writtenBytesTotal));
			mHolder.speed.setText(NetWorkSpeedUtils
					.speedFormatter(downloadSpeed));
			RemoteViews views = new RemoteViews(getPackageName(),
					R.layout.view_download_notification);
			views.setTextViewText(R.id.title, mAppInfo.getAppName());
			views.setImageViewResource(R.id.icon, R.drawable.ic_launcher);
			views.setViewVisibility(R.id.progressbar, View.VISIBLE);
			notification = notificationFactory.create(views);
			views.setProgressBar(R.id.progressbar, mContentLength,
					writtenBytesTotal, false);
			// 通知栏提示任务进度
			sendNotification(getTaskId(mDownloader), notification);
		}

		@Override
		public void onPaused(int writtenBytesLength) {
			clearRecordTime();
			outageTime = System.currentTimeMillis();

		}

		@Override
		public void onFinished(String tragetFilePatch) {
			mHolder.button.setText("重新下载");
			mHolder.speed.setVisibility(View.INVISIBLE);
			Intent intent = new Intent(Intent.ACTION_VIEW);
			intent.setDataAndType(
					Uri.parse("file://"
							+ mDownloader.getTemporaryFile().getAbsolutePath()),
					"application/vnd.android.package-archive");
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			RemoteViews views = new RemoteViews(getPackageName(),
					R.layout.view_download_notification);
			views.setTextViewText(R.id.title, mAppInfo.getAppName());
			views.setTextViewText(R.id.title_text,
					getResources().getString(R.string.download_finished));
			views.setViewVisibility(R.id.title_text, View.VISIBLE);
			views.setImageViewResource(R.id.icon, R.drawable.ic_launcher);
			views.setViewVisibility(R.id.progressbar, View.INVISIBLE);
			notification = notificationFactory.setIntent(intent).create(views);
			notification.flags = Notification.FLAG_AUTO_CANCEL;
			sendNotification(getTaskId(mDownloader), notification);
			taskQueue.remove(mDownloader);
			ToastUtils.info((Activity) mContext, R.string.download_finished);
		}

		@Override
		public void onCanceled() {
			mHolder.button.setText("下载");
			mHolder.pargressBar.setVisibility(View.INVISIBLE);
			mHolder.speed.setVisibility(View.INVISIBLE);
			cancleNotification(getTaskId(mDownloader));
			taskQueue.remove(mDownloader);
		}

	}

	private Downloader download(Context context, AppInfo appInfo, Object holder) {
		if (null == holder) {
			return null;
		}
		if (!(holder instanceof ViewHolder)) {
			return null;
		}

		holder = (ViewHolder) holder;
		Downloader downloader = new FileDownloader(appInfo.getAppUrl(),
				mDownloadOptions);
		downloader.setOnDownloadListener(new ServiceDownloadListener(context,
				holder, appInfo, downloader));
		addDownloadTask(downloader);
		return downloader;
	}

	private void reDownload(Downloader downloader) {
		if (null == downloader) {
			return;
		}
		if (taskQueue.contains(downloader)) {
			downloader.redownload();
		}
	}

	private void cancel(Downloader downloader) {
		if (null == downloader) {
			return;
		}
		downloader.cancel();
	}

	private void cancelAll() {
		taskQueue.removeAll();
	}

	private void pause(Downloader downloader) {
		if (null == downloader) {
			return;
		}
		// if (taskList.contains(downloader)) {
		// downloader.pause();
		// }
	}

	private int getTaskId(Downloader downloader) {
		if (taskQueue.contains(downloader)) {
			return downloader.hashCode();
		}
		// not found taksId
		return -1;
	}

	private class ServiceNotificationFactory {
		private Context mContext;
		private Builder mBuilder;
		private Notification notification;
		private Intent mIntent;

		public ServiceNotificationFactory(Context context) {
			mContext = context;
			mIntent = new Intent(DownloadService.this, DemoActivity.class);
			PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
					mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
			mBuilder = new Notification.Builder(mContext);
			mBuilder.setAutoCancel(true);
			mBuilder.setContentIntent(pendingIntent);
			mBuilder.setSmallIcon(R.drawable.ic_launcher);
		}

		public ServiceNotificationFactory setIntent(Intent intent) {
			mIntent = intent;
			return this;
		}

		public Notification create(RemoteViews views) {
			notification = mBuilder.build();
			notification.contentView = views;
			notification.flags = Notification.FLAG_ONGOING_EVENT;
			return notification;
		}
	}

}